package cn.geekyspace.scanhive.serial.receiver;

import cn.geekyspace.scanhive.pojo.entity.CleaningData;
import cn.geekyspace.scanhive.service.CleaningDataService;
import cn.geekyspace.scanhive.utils.UIUpdater;
import com.fazecast.jSerialComm.SerialPort;
import javafx.scene.control.CheckBox;
import javafx.scene.paint.Color;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 扫描仪（扫码枪）数据接收器
 */
@Slf4j
@Data
@Component
@RequiredArgsConstructor
public class ScannerDataReceiver {

    // 正则表达式匹配日期格式 yyyy-MM-dd
    private static final String DATE_PATTERN = "\\d{4}-\\d{2}-\\d{2}";

    // 使用原子布尔值来控制线程
    private final AtomicBoolean keepReceiving = new AtomicBoolean(false);

    // 当前处理的串口
    private SerialPort currentPort;

    // 串口接收线程
    private Thread receiveThread;

    // 注入UI更新器
    private final UIUpdater uiUpdater;
    private final CleaningDataService cleaningDataService;

    /**
     * 开始监听接收数据
     */
    public synchronized void startReceivingData(SerialPort port) {
        if (port.isOpen() && !keepReceiving.get()) {
            this.currentPort = port;
            this.keepReceiving.set(true);

            log.info("开始监听扫码枪串口: {}", port.getSystemPortName());

            receiveThread = new Thread(() -> {
                try (InputStream inputStream = port.getInputStream()) {
                    while (keepReceiving.get() && port.isOpen()) {
                        // 检查是否有可用数据
                        int available = inputStream.available();
                        if (available == 0) {
                            Thread.sleep(100); // 没有数据可读时休眠
                            continue;
                        }

                        // 读取数据
                        byte[] buffer = new byte[available];
                        int bytesRead = inputStream.read(buffer);
                        if (bytesRead > 0) {
                            // 数据处理逻辑：将数据转换为十六进制字符串（ASCII 码字符串）
                            String receiveText = processData(buffer, bytesRead);
                            log.info("扫码枪接收 数据转文本: " + receiveText);

                            // 调用处理方法
                            handleReceivedData(receiveText, true);
                        }
                    }
                } catch (InterruptedException e) {
                    log.warn("接收线程被中断: {}", e.getMessage());
                } catch (IOException e) {
                    log.error("读取串口数据时发生错误: {}", e.getMessage());
                } finally {
                    cleanupResources();
                }
            });

            receiveThread.setName("SerialPort-Receive-Thread");
            receiveThread.start();
        } else {
            log.warn("串口未打开或已经在接收数据: {}", port.getSystemPortName());
        }
    }

    /**
     * 停止监听数据
     */
    public synchronized void stopReceivingData() {
        if (keepReceiving.getAndSet(false)) {
            log.info("正在停止扫码枪数据接收...");
            if (currentPort != null && currentPort.isOpen()) {
                try {
                    currentPort.closePort();
                    log.info("成功关闭串口: {}", currentPort.getSystemPortName());
                } catch (Exception e) {
                    log.error("关闭串口时发生错误: {}", e.getMessage());
                }
            }
            if (receiveThread != null && receiveThread.isAlive()) {
                receiveThread.interrupt();
                log.info("接收线程已中断");
            }
        } else {
            log.warn("接收线程已经停止或未启动");
        }
    }

    /**
     * 清理资源
     */
    private synchronized void cleanupResources() {
        if (currentPort != null) {
            if (currentPort.isOpen()) {
                currentPort.closePort();
                log.info("释放串口资源: {}", currentPort.getSystemPortName());
            }
            currentPort = null;
        }
    }

    /**
     * 数据处理逻辑：将字节数组转为十六进制字符串
     */
    private String processData(byte[] buffer, int bytesRead) {
        StringBuilder hexData = new StringBuilder();
        for (int i = 0; i < bytesRead; i++) {
            hexData.append(String.format("%02x", buffer[i]).toUpperCase(Locale.ROOT));
            if (i < bytesRead - 1) {
                hexData.append(" "); // 用空格分隔
            }
        }
        // ASCII 编码的16进制字符串
        String asciiHexData = hexData.toString();
        log.info("扫码枪接收 ASCII数据: {}", asciiHexData);

        return hexToString(asciiHexData);
    }

    /**
     * 将十六进制字符串转换为普通字符串
     * @param hexData 带空格的十六进制字符串
     * @return 转换后的普通字符串
     */
    public static String hexToString(String hexData) {
        StringBuilder output = new StringBuilder();
        // 去除字符串中的空格
        String[] hexArray = hexData.split(" ");
        for (String hex : hexArray) {
            // 将每个十六进制字符转换为对应的ASCII字符
            int decimal = Integer.parseInt(hex, 16);
            output.append((char) decimal);
        }
        return output.toString();
    }

    /**
     * 处理接收到的数据
     */
    public void handleReceivedData(String receiveText, Boolean isAutoStorage) {
        //waitingForTestResult = true; 时要先等待测试结果

        uiUpdater.updateScanText(receiveText);                     // 清空并设置新的文本
        boolean status = uiUpdater.checkScanStatus(receiveText);   // 判断扫描状态（OK/NG）
        uiUpdater.updateScanStatusLabel(status);                   // 根据状态设置扫描状态标签

        // 判断是否需要等待测试结果
        if (uiUpdater.isWaitingForTestResult()) {
            uiUpdater.setLogMessage("正在等待测试结果，请稍后...", Color.ORANGE);
            return; // 如果需要等待测试结果，直接返回，不执行后续的入库操作
        }

        // 判断是否勾选自动入库
        CheckBox autoStorage = uiUpdater.getAutoStorage();
        if ((!isAutoStorage || autoStorage.isSelected()) && status) {
            // 执行自动入库逻辑
            CleaningData cleaningData = cleaningDataService.saveQrCodeData(receiveText);
            uiUpdater.addScanRecord(cleaningData);                 // 更新扫描记录
            uiUpdater.setLogMessage(isAutoStorage ? "自动入库成功，等待测试结果" : "手动入库成功，等待测试结果", Color.GREEN);
        } else {
            uiUpdater.setLogMessage("数据NG 或 未勾选自动入库", Color.RED);
        }
    }

}
